pub struct DesUtil;

impl DesUtil {
    pub const KEY1: &'static str = "678";
    pub const KEY2: &'static str = "123";
    pub const KEY3: &'static str = "";

    /// 主加密方法，与Java的strEnc方法完全对应
    pub fn str_enc(data: &str, first_key: &str, second_key: &str, third_key: &str) -> String {
        let leng = data.len();
        let mut enc_data = String::new();

        let (first_key_bt, first_length) = if !first_key.is_empty() {
            let keys = Self::get_key_bytes(first_key);
            let len = keys.len();
            (Some(keys), len)
        } else {
            (None, 0)
        };

        let (second_key_bt, second_length) = if !second_key.is_empty() {
            let keys = Self::get_key_bytes(second_key);
            let len = keys.len();
            (Some(keys), len)
        } else {
            (None, 0)
        };

        let (third_key_bt, third_length) = if !third_key.is_empty() {
            let keys = Self::get_key_bytes(third_key);
            let len = keys.len();
            (Some(keys), len)
        } else {
            (None, 0)
        };

        if leng > 0 {
            if leng < 4 {
                let bt = Self::str_to_bt(data);
                let enc_byte = Self::encrypt_with_keys(
                    bt,
                    &first_key_bt, first_length,
                    &second_key_bt, second_length,
                    &third_key_bt, third_length
                );
                enc_data = Self::bt64_to_hex(&enc_byte);
            } else {
                let iterator = leng / 4;
                let remainder = leng % 4;

                for i in 0..iterator {
                    let temp_data = &data[i * 4..i * 4 + 4];
                    let temp_byte = Self::str_to_bt(temp_data);
                    let enc_byte = Self::encrypt_with_keys(
                        temp_byte,
                        &first_key_bt, first_length,
                        &second_key_bt, second_length,
                        &third_key_bt, third_length
                    );
                    enc_data.push_str(&Self::bt64_to_hex(&enc_byte));
                }

                if remainder > 0 {
                    let remainder_data = &data[iterator * 4..];
                    let temp_byte = Self::str_to_bt(remainder_data);
                    let enc_byte = Self::encrypt_with_keys(
                        temp_byte,
                        &first_key_bt, first_length,
                        &second_key_bt, second_length,
                        &third_key_bt, third_length
                    );
                    enc_data.push_str(&Self::bt64_to_hex(&enc_byte));
                }
            }
        }
        enc_data
    }

    fn encrypt_with_keys(
        mut bt: [i32; 64],
        first_key_bt: &Option<Vec<[i32; 64]>>, first_length: usize,
        second_key_bt: &Option<Vec<[i32; 64]>>, second_length: usize,
        third_key_bt: &Option<Vec<[i32; 64]>>, third_length: usize
    ) -> [i32; 64] {
        if let (Some(first), Some(second), Some(third)) = (first_key_bt, second_key_bt, third_key_bt) {
            for x in 0..first_length {
                bt = Self::enc(bt, first[x]);
            }
            for y in 0..second_length {
                bt = Self::enc(bt, second[y]);
            }
            for z in 0..third_length {
                bt = Self::enc(bt, third[z]);
            }
        } else if let (Some(first), Some(second)) = (first_key_bt, second_key_bt) {
            for x in 0..first_length {
                bt = Self::enc(bt, first[x]);
            }
            for y in 0..second_length {
                bt = Self::enc(bt, second[y]);
            }
        } else if let Some(first) = first_key_bt {
            for x in 0..first_length {
                bt = Self::enc(bt, first[x]);
            }
        }
        bt
    }

    fn get_key_bytes(key: &str) -> Vec<[i32; 64]> {
        let mut key_bytes = Vec::new();
        let leng = key.len();
        let iterator = leng / 4;
        let remainder = leng % 4;

        for i in 0..iterator {
            key_bytes.push(Self::str_to_bt(&key[i * 4..i * 4 + 4]));
        }

        if remainder > 0 {
            key_bytes.push(Self::str_to_bt(&key[iterator * 4..]));
        }

        key_bytes
    }

    fn str_to_bt(s: &str) -> [i32; 64] {
        let mut bt = [0i32; 64];
        let leng = s.len();
        let chars: Vec<char> = s.chars().collect();

        if leng < 4 {
            for i in 0..leng {
                let k = chars[i] as u32;
                for j in 0..16 {
                    // 修复：使用安全的幂运算，避免溢出
                    let pow = 1u32 << (15 - j); // 2^(15-j)
                    bt[16 * i + j] = ((k / pow) % 2) as i32;
                }
            }
            for p in leng..4 {
                let k = 0u32;
                for q in 0..16 {
                    let pow = 1u32 << (15 - q); // 2^(15-q)
                    bt[16 * p + q] = ((k / pow) % 2) as i32;
                }
            }
        } else {
            for i in 0..4 {
                let k = chars[i] as u32;
                for j in 0..16 {
                    // 修复：使用位移运算代替循环乘法
                    let pow = 1u32 << (15 - j); // 2^(15-j)
                    bt[16 * i + j] = ((k / pow) % 2) as i32;
                }
            }
        }
        bt
    }

    fn bt64_to_hex(byte_data: &[i32; 64]) -> String {
        let mut hex = String::new();
        for i in 0..16 {
            let mut bt = String::new();
            for j in 0..4 {
                bt.push_str(&byte_data[i * 4 + j].to_string());
            }
            hex.push_str(&Self::bt4_to_hex(&bt));
        }
        hex
    }

    fn bt4_to_hex(binary: &str) -> String {
        match binary {
            "0000" => "0".to_string(),
            "0001" => "1".to_string(),
            "0010" => "2".to_string(),
            "0011" => "3".to_string(),
            "0100" => "4".to_string(),
            "0101" => "5".to_string(),
            "0110" => "6".to_string(),
            "0111" => "7".to_string(),
            "1000" => "8".to_string(),
            "1001" => "9".to_string(),
            "1010" => "A".to_string(),
            "1011" => "B".to_string(),
            "1100" => "C".to_string(),
            "1101" => "D".to_string(),
            "1110" => "E".to_string(),
            "1111" => "F".to_string(),
            _ => "".to_string(),
        }
    }

    fn enc(data_byte: [i32; 64], key_byte: [i32; 64]) -> [i32; 64] {
        let keys = Self::generate_keys(key_byte);
        let ip_byte = Self::init_permute(data_byte);
        let mut ip_left = [0i32; 32];
        let mut ip_right = [0i32; 32];

        for k in 0..32 {
            ip_left[k] = ip_byte[k];
            ip_right[k] = ip_byte[32 + k];
        }

        for i in 0..16 {
            let temp_left = ip_left;
            ip_left = ip_right;

            let key = keys[i];
            let temp_right = Self::xor(
                &Self::p_permute(Self::s_box_permute(Self::xor(
                    &Self::expand_permute(ip_right), &key
                ))),
                &temp_left
            );

            for n in 0..32 {
                ip_right[n] = temp_right[n];
            }
        }

        let mut final_data = [0i32; 64];
        for i in 0..32 {
            final_data[i] = ip_right[i];
            final_data[32 + i] = ip_left[i];
        }

        Self::finally_permute(final_data)
    }

    fn init_permute(original_data: [i32; 64]) -> [i32; 64] {
        let mut ip_byte = [0i32; 64];
        let mut m = 1;
        let mut n = 0;

        for i in 0..4 {
            let mut k = 0;
            for j in (0..8).rev() {
                ip_byte[i * 8 + k] = original_data[j * 8 + m];
                ip_byte[i * 8 + k + 32] = original_data[j * 8 + n];
                k += 1;
            }
            m += 2;
            n += 2;
        }
        ip_byte
    }

    fn expand_permute(right_data: [i32; 32]) -> [i32; 48] {
        let mut ep_byte = [0i32; 48];

        for i in 0..8 {
            ep_byte[i * 6 + 0] = if i == 0 {
                right_data[31]
            } else {
                right_data[i * 4 - 1]
            };
            ep_byte[i * 6 + 1] = right_data[i * 4 + 0];
            ep_byte[i * 6 + 2] = right_data[i * 4 + 1];
            ep_byte[i * 6 + 3] = right_data[i * 4 + 2];
            ep_byte[i * 6 + 4] = right_data[i * 4 + 3];
            ep_byte[i * 6 + 5] = if i == 7 {
                right_data[0]
            } else {
                right_data[i * 4 + 4]
            };
        }
        ep_byte
    }

    fn xor(byte_one: &[i32], byte_two: &[i32]) -> Vec<i32> {
        let mut xor_byte = vec![0; byte_one.len()];
        for i in 0..byte_one.len() {
            xor_byte[i] = byte_one[i] ^ byte_two[i];
        }
        xor_byte
    }

    fn s_box_permute(expand_byte: Vec<i32>) -> [i32; 32] {
        let mut s_box_byte = [0i32; 32];

        let s1 = [
            [14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],
            [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],
            [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],
            [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]
        ];

        let s2 = [
            [15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10],
            [3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5],
            [0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15],
            [13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9]
        ];

        let s3 = [
            [10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8],
            [13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1],
            [13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7],
            [1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12]
        ];

        let s4 = [
            [7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15],
            [13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9],
            [10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4],
            [3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14]
        ];

        let s5 = [
            [2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9],
            [14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6],
            [4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14],
            [11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3]
        ];

        let s6 = [
            [12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11],
            [10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8],
            [9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6],
            [4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13]
        ];

        let s7 = [
            [4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1],
            [13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6],
            [1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2],
            [6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12]
        ];

        let s8 = [
            [13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7],
            [1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2],
            [7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8],
            [2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11]
        ];

        let s_boxes = [s1, s2, s3, s4, s5, s6, s7, s8];

        for m in 0..8 {
            let i = (expand_byte[m * 6 + 0] * 2 + expand_byte[m * 6 + 5]) as usize;
            let j = (expand_byte[m * 6 + 1] * 8 + expand_byte[m * 6 + 2] * 4 +
                expand_byte[m * 6 + 3] * 2 + expand_byte[m * 6 + 4]) as usize;

            let binary = Self::get_box_binary(s_boxes[m][i][j]);

            s_box_byte[m * 4 + 0] = binary.chars().nth(0).unwrap().to_digit(10).unwrap() as i32;
            s_box_byte[m * 4 + 1] = binary.chars().nth(1).unwrap().to_digit(10).unwrap() as i32;
            s_box_byte[m * 4 + 2] = binary.chars().nth(2).unwrap().to_digit(10).unwrap() as i32;
            s_box_byte[m * 4 + 3] = binary.chars().nth(3).unwrap().to_digit(10).unwrap() as i32;
        }
        s_box_byte
    }

    fn get_box_binary(i: i32) -> String {
        match i {
            0 => "0000".to_string(),
            1 => "0001".to_string(),
            2 => "0010".to_string(),
            3 => "0011".to_string(),
            4 => "0100".to_string(),
            5 => "0101".to_string(),
            6 => "0110".to_string(),
            7 => "0111".to_string(),
            8 => "1000".to_string(),
            9 => "1001".to_string(),
            10 => "1010".to_string(),
            11 => "1011".to_string(),
            12 => "1100".to_string(),
            13 => "1101".to_string(),
            14 => "1110".to_string(),
            15 => "1111".to_string(),
            _ => "0000".to_string(),
        }
    }

    fn p_permute(s_box_byte: [i32; 32]) -> [i32; 32] {
        let mut p_box_permute = [0i32; 32];
        p_box_permute[0] = s_box_byte[15];
        p_box_permute[1] = s_box_byte[6];
        p_box_permute[2] = s_box_byte[19];
        p_box_permute[3] = s_box_byte[20];
        p_box_permute[4] = s_box_byte[28];
        p_box_permute[5] = s_box_byte[11];
        p_box_permute[6] = s_box_byte[27];
        p_box_permute[7] = s_box_byte[16];
        p_box_permute[8] = s_box_byte[0];
        p_box_permute[9] = s_box_byte[14];
        p_box_permute[10] = s_box_byte[22];
        p_box_permute[11] = s_box_byte[25];
        p_box_permute[12] = s_box_byte[4];
        p_box_permute[13] = s_box_byte[17];
        p_box_permute[14] = s_box_byte[30];
        p_box_permute[15] = s_box_byte[9];
        p_box_permute[16] = s_box_byte[1];
        p_box_permute[17] = s_box_byte[7];
        p_box_permute[18] = s_box_byte[23];
        p_box_permute[19] = s_box_byte[13];
        p_box_permute[20] = s_box_byte[31];
        p_box_permute[21] = s_box_byte[26];
        p_box_permute[22] = s_box_byte[2];
        p_box_permute[23] = s_box_byte[8];
        p_box_permute[24] = s_box_byte[18];
        p_box_permute[25] = s_box_byte[12];
        p_box_permute[26] = s_box_byte[29];
        p_box_permute[27] = s_box_byte[5];
        p_box_permute[28] = s_box_byte[21];
        p_box_permute[29] = s_box_byte[10];
        p_box_permute[30] = s_box_byte[3];
        p_box_permute[31] = s_box_byte[24];
        p_box_permute
    }

    fn finally_permute(end_byte: [i32; 64]) -> [i32; 64] {
        let mut fp_byte = [0i32; 64];
        fp_byte[0] = end_byte[39]; fp_byte[1] = end_byte[7]; fp_byte[2] = end_byte[47]; fp_byte[3] = end_byte[15];
        fp_byte[4] = end_byte[55]; fp_byte[5] = end_byte[23]; fp_byte[6] = end_byte[63]; fp_byte[7] = end_byte[31];
        fp_byte[8] = end_byte[38]; fp_byte[9] = end_byte[6]; fp_byte[10] = end_byte[46]; fp_byte[11] = end_byte[14];
        fp_byte[12] = end_byte[54]; fp_byte[13] = end_byte[22]; fp_byte[14] = end_byte[62]; fp_byte[15] = end_byte[30];
        fp_byte[16] = end_byte[37]; fp_byte[17] = end_byte[5]; fp_byte[18] = end_byte[45]; fp_byte[19] = end_byte[13];
        fp_byte[20] = end_byte[53]; fp_byte[21] = end_byte[21]; fp_byte[22] = end_byte[61]; fp_byte[23] = end_byte[29];
        fp_byte[24] = end_byte[36]; fp_byte[25] = end_byte[4]; fp_byte[26] = end_byte[44]; fp_byte[27] = end_byte[12];
        fp_byte[28] = end_byte[52]; fp_byte[29] = end_byte[20]; fp_byte[30] = end_byte[60]; fp_byte[31] = end_byte[28];
        fp_byte[32] = end_byte[35]; fp_byte[33] = end_byte[3]; fp_byte[34] = end_byte[43]; fp_byte[35] = end_byte[11];
        fp_byte[36] = end_byte[51]; fp_byte[37] = end_byte[19]; fp_byte[38] = end_byte[59]; fp_byte[39] = end_byte[27];
        fp_byte[40] = end_byte[34]; fp_byte[41] = end_byte[2]; fp_byte[42] = end_byte[42]; fp_byte[43] = end_byte[10];
        fp_byte[44] = end_byte[50]; fp_byte[45] = end_byte[18]; fp_byte[46] = end_byte[58]; fp_byte[47] = end_byte[26];
        fp_byte[48] = end_byte[33]; fp_byte[49] = end_byte[1]; fp_byte[50] = end_byte[41]; fp_byte[51] = end_byte[9];
        fp_byte[52] = end_byte[49]; fp_byte[53] = end_byte[17]; fp_byte[54] = end_byte[57]; fp_byte[55] = end_byte[25];
        fp_byte[56] = end_byte[32]; fp_byte[57] = end_byte[0]; fp_byte[58] = end_byte[40]; fp_byte[59] = end_byte[8];
        fp_byte[60] = end_byte[48]; fp_byte[61] = end_byte[16]; fp_byte[62] = end_byte[56]; fp_byte[63] = end_byte[24];
        fp_byte
    }

    fn generate_keys(key_byte: [i32; 64]) -> [[i32; 48]; 16] {
        let mut key = [0i32; 56];
        let mut keys = [[0i32; 48]; 16];
        let loop_arr = [1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1];

        for i in 0..7 {
            let mut k = 7;
            for j in 0..8 {
                key[i * 8 + j] = key_byte[8 * k + i];
                if k > 0 {
                    k -= 1;
                }
            }
        }

        for i in 0..16 {
            for _ in 0..loop_arr[i] {
                let temp_left = key[0];
                let temp_right = key[28];
                for k in 0..27 {
                    key[k] = key[k + 1];
                    key[28 + k] = key[29 + k];
                }
                key[27] = temp_left;
                key[55] = temp_right;
            }

            let mut temp_key = [0i32; 48];
            temp_key[0] = key[13]; temp_key[1] = key[16]; temp_key[2] = key[10]; temp_key[3] = key[23];
            temp_key[4] = key[0]; temp_key[5] = key[4]; temp_key[6] = key[2]; temp_key[7] = key[27];
            temp_key[8] = key[14]; temp_key[9] = key[5]; temp_key[10] = key[20]; temp_key[11] = key[9];
            temp_key[12] = key[22]; temp_key[13] = key[18]; temp_key[14] = key[11]; temp_key[15] = key[3];
            temp_key[16] = key[25]; temp_key[17] = key[7]; temp_key[18] = key[15]; temp_key[19] = key[6];
            temp_key[20] = key[26]; temp_key[21] = key[19]; temp_key[22] = key[12]; temp_key[23] = key[1];
            temp_key[24] = key[40]; temp_key[25] = key[51]; temp_key[26] = key[30]; temp_key[27] = key[36];
            temp_key[28] = key[46]; temp_key[29] = key[54]; temp_key[30] = key[29]; temp_key[31] = key[39];
            temp_key[32] = key[50]; temp_key[33] = key[44]; temp_key[34] = key[32]; temp_key[35] = key[47];
            temp_key[36] = key[43]; temp_key[37] = key[48]; temp_key[38] = key[38]; temp_key[39] = key[55];
            temp_key[40] = key[33]; temp_key[41] = key[52]; temp_key[42] = key[45]; temp_key[43] = key[41];
            temp_key[44] = key[49]; temp_key[45] = key[35]; temp_key[46] = key[28]; temp_key[47] = key[31];

            keys[i] = temp_key;
        }
        keys
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_des_encryption() {
        let result = DesUtil::str_enc("20250701", DesUtil::KEY1, DesUtil::KEY2, DesUtil::KEY3);
        println!("20250701 -> {}", result);

        // 测试与Java版本的一致性
        let test_data = "test";
        let encrypted = DesUtil::str_enc(test_data, "678", "123", "");
        println!("{} -> {}", test_data, encrypted);
    }
}